#ifndef LOOSE_VERSION_H
#define LOOSE_VERSION_H

#include <string>
#include <vector>
#include <boost/tokenizer.hpp>

/**
 * @brief The CLooseVersion class version信息包装
 */
class CLooseVersion
{
public:
    /**
     * @brief CLooseVersion
     * @param vstring
     */
    CLooseVersion(const char *vstring)
    {
        if (NULL != vstring)
        {
            this->parse(vstring);
        }
    }

    /**
     * @brief parse
     * @param vstring
     */
    void parse(const char *vstring)
    {
        m_vstring = vstring;
        boost::char_separator<char> sep(".");
        boost::tokenizer< boost::char_separator<char> > tokens(m_vstring, sep);

        m_iversion.clear();
        for (boost::tokenizer< boost::char_separator<char> >::iterator iter = tokens.begin(); iter != tokens.end(); ++iter)
        {
            m_iversion.push_back(atoi((*iter).c_str()));
        }
    }

    /**
     * @brief version
     * @return
     */
    const char *version() const
    {
        return m_vstring.c_str();
    }

    /**
     * @brief operator <
     * @param version
     * @return
     */
    bool operator < (const CLooseVersion &version) const
    {
        return this->cmp(version) == -1;
    }

    bool operator == (const CLooseVersion &version) const
    {
        return this->cmp(version) == 0;
    }

    bool operator > (const CLooseVersion &version) const
    {
        return this->cmp(version) == 1;
    }

    bool operator <= (const CLooseVersion &version) const
    {
        int rc = this->cmp(version);
        if (rc == -1 || rc == 0)
        {
            return true;
        }
        return false;
    }

    bool operator >= (const CLooseVersion &version) const
    {
        int rc = this->cmp(version);
        if (rc == 1 || rc == 0)
        {
            return true;
        }
        return false;
    }

private:
    /**
     * @brief cmp 比较
     * @param other other version
     * @return -1 L, 0E, 1 G
     */
    int cmp(const CLooseVersion &other) const
    {
        const std::vector<int32_t> *left = &(this->m_iversion);
        const std::vector<int32_t> *right = &(other.m_iversion);
        bool left_is_self = true;

        if (left->size() < right->size())
        {
            left = &(other.m_iversion);
            right = &(this->m_iversion);
            left_is_self = false;
        }

        size_t left_size = left->size();
        int rc = 0;
        for (size_t var = 0; var < left_size; ++var)
        {
            if ((*left)[var] < (*right)[var])
            {
                rc = -1;
                break;
            }
            else if ((*left)[var] > (*right)[var])
            {
                rc = 1;
                break;
            }
            else
            {
                continue;
            }
        }

        // 如果最短匹配都相同，则长的获胜
        if (0 == rc)
        {
            if (left->size() > right->size())           // 左边大
            {
                return left_is_self ? 1 : -1;           // 左边是自己，那就大于
            }
            else if (left->size() < right->size())      // 右边大
            {
                return left_is_self ? -1 : 1;           // 左边是自己，那就小于
            }
            else                                        // 一样大
            {
                return 0;
            }
        }
        return left_is_self ? rc : -rc;                 // 左边是自己，匹配结果就是正确大，如果左边是别人，那就是反的
    }
private:
    std::string m_vstring;
    std::vector<int32_t> m_iversion;
};

#endif // LOOSE_VERSION_H
